#include "finsh_config.h"

#ifdef FINSH_ENABLE

#include "finsh.h"
#include "finsh_system.h"
#include <stdlib.h>
#include <string.h>

#include "malloc.h"


/*
http://patorjk.com/software/taag/#p=display&f=Graffiti&t=
   ____            ___  __________  ____  ______       ____
  / __/______ ___ / _ \/_  __/ __ \/ __/ / __/ /  ___ / / /
 / _// __/ -_) -_) , _/ / / / /_/ /\ \  _\ \/ _ \/ -_) / / 
/_/ /_/  \__/\__/_/|_| /_/  \____/___/ /___/_//_/\__/_/_/  

*/

const char system_log1[] = "   ____            ___  __________  ____  ______       ____";
const char system_log2[] = "  / __/______ ___ / _ \\/_  __/ __ \\/ __/ / __/ /  ___ / / /";
const char system_log3[] = " / _// __/ -_) -_) , _/ / / / /_/ /\\ \\  _\\ \\/ _ \\/ -_) / / ";
const char system_log4[] = "/_/ /_/  \\__/\\__/_/|_| /_/  \\____/___/ /___/_//_/\\__/_/_/  ";

void finsh_system_show_version(void)
{
	finsh_printf("\n");
#if 0
	finsh_printf("%s\n", system_log1);
	finsh_printf("%s\n", system_log2);
	finsh_printf("%s\n", system_log3);
	finsh_printf("%s\n", system_log4);
	
	finsh_printf(" * FreeRTOS:%s \n",tskKERNEL_VERSION_NUMBER);
	finsh_printf(" * Shell:V%s \n", FINSH_VERSION);
	finsh_printf(" * build %s\n", __DATE__);

#else
	finsh_printf("\033[0;34m%s\033[0m\n", system_log1);
	finsh_printf("\033[0;34m%s\033[0m * FreeRTOS:%s \n", system_log2, os_get_version());
	finsh_printf("\033[0;34m%s\033[0m * Shell:V%s \n", system_log3, FINSH_VERSION);
	finsh_printf("\033[0;34m%s\033[0m * build %s\n", system_log4, __DATE__);
#endif	
	finsh_printf("\n");
}

static __inline void object_split(int len)
{
    while (len--) finsh_printf("-");
	finsh_printf("\n");
}


void finsh_system_ps(void)
{
	int ret = 0;
	uint32_t idx, num;
	os_task_status_t **task_sta = NULL;

	object_split(FINSH_CMD_SIZE);

	num = os_get_task_nums();
	task_sta = malloc(sizeof(void*) * num);
	if (task_sta == NULL)
	{
		ret = -1;
		LOG_E("malloc **p fail\n");
	}
	else
	{
		for (idx=0; idx<num; idx++)
		{
			task_sta[idx] = malloc(sizeof(os_task_status_t));
			if (task_sta[idx] == NULL)
			{
				ret = -1;
				LOG_E("malloc p[%d] fail\n", idx);
				break;
			}
			else
			{
				memset(task_sta[idx], 0x00, sizeof(os_task_status_t));
			}
		}
	}
	
	if (ret == 0)
	{
		finsh_printf("\t%-16s", "Task Name");
		finsh_printf("STAT\tPRIO\tSTACK\tID\t");
		finsh_printf("CNT\t\t%%CPU\n");
		
		os_get_task_status(task_sta);
		
		for (idx=0; idx<num; idx++)
		{
			finsh_printf("\t%-16s",task_sta[idx]->name);
			finsh_printf("%c\t%u\t%u\t%u\t", task_sta[idx]->status, task_sta[idx]->prio, task_sta[idx]->free_stk, task_sta[idx]->id);

			if (task_sta[idx]->run_time != -1)
			{
				if( task_sta[idx]->usage > 0UL )
				{
					finsh_printf("%u\t\t%u%%", task_sta[idx]->run_time, task_sta[idx]->usage);
				}
				else
				{
					finsh_printf("%u\t\t<1%%", task_sta[idx]->run_time);
				}
			}
			finsh_printf("\n");
		}
	}

	for (idx=0; idx<num; idx++)
	{
		free(task_sta[idx]);
	}
	free(task_sta);

	object_split(FINSH_CMD_SIZE);
}

int finsh_system_kill(int argc, char **argv)
{
	int ret = 0;
	uint32_t idx, num, id;
	os_task_handle_t task_handle = NULL;
	os_task_status_t **task_sta = NULL;


	if (argc != 2)
	{
		finsh_printf("Usage : kill <pid>\n");
		finsh_printf("OPTIONS:\n");
		finsh_printf("\t<pid>, ID of task\n");
		return -1;
	}
	
	id = atoi(argv[1]);

	num = os_get_task_nums();
	task_sta = malloc(sizeof(void*) * num);
	if (task_sta == NULL)
	{
		ret = -1;
		LOG_E("malloc **p fail\n");
	}
	else
	{
		for (idx=0; idx<num; idx++)
		{
			task_sta[idx] = malloc(sizeof(os_task_status_t));
			if (task_sta[idx] == NULL)
			{
				ret = -1;
				LOG_E("malloc p[%d] fail\n", idx);
				break;
			}
			else
			{
				memset(task_sta[idx], 0x00, sizeof(os_task_status_t));
			}
		}
	}
	
	if (ret == 0)
	{
		os_get_task_status(task_sta);

		for(idx=0; idx<num; idx++)
		{
			if (task_sta[idx]->id == id)
			{
				task_handle = task_sta[idx]->task_handle;
				os_task_delete(task_handle, NULL);		/* delete the task */
				// LOG_I("task '%s' killed!\n", task_sta[idx].name);
				break;
			}
		}
		if (idx >= num)
		{
			finsh_printf("task not found\n");
		}
	}

	return ret;
}

int finsh_system_free(int argc, char **argv)
{

	int ret = 0;
#if 1
	uint32_t total, used, free, usage;
	uint32_t mul;
	char unit = 0;
	
	if(argc == 1)
	{
		unit = 0;
	}
	else if(argc == 2)
	{
		if (strncmp(argv[1], "-b", 2) == 0) unit = 0;
		else if (strncmp(argv[1], "-k", 2) == 0) unit = 'K';
		else if (strncmp(argv[1], "-m", 2) == 0) unit = 'M';
		else if (strncmp(argv[1], "-g", 2) == 0) unit = 'G';
		else ret = -1; 
	}
	else 
	{
		ret = -1;
	}
	
	if (ret)
	{
		finsh_printf("Usage : mem [OPTIONS]\n");
		finsh_printf("OPTIONS:\n");
		finsh_printf("\t-b, --bytes\n");
		finsh_printf("\t-k, --kibi\n");
		finsh_printf("\t-m, --mebi\n");
		finsh_printf("\t-g, --gibi\n");
		return -1;
	}
	
	switch(unit)
	{
		case 'K': mul = 1024; break;
		case 'M': mul = 1024*1024; break;
		case 'G': mul = 1024*1024*1024; break;
		default: mul = 1; break;
	}

	object_split(80);
	finsh_printf("%24s%12s%12s%12s\n","total", "used", "free", "usage");
	finsh_printf("%-12s", "Mem OS:");
	
	total = os_get_heap_total_size();
	free = os_get_heap_free_size();
	used = total - free;
	usage = (used * 100) / total;
	if (unit == 0)
	{
		finsh_printf("%12d%12d%12d%11d%%\n",total, used, free, usage);
	}
	else
	{
		total = total / mul;
		used = used / mul;
		free = free / mul;
		finsh_printf("%10d %c%10d %c%10d %c%11d%%\n",total, unit, used, unit, free, unit,  usage);
	}
#ifdef __MALLOC_H

	finsh_printf("%-12s", "SRAM IN:");
	
	total = mem_get_total_size();
	used = mem_get_used_size();
	free = total - used;
	usage = (used * 100) / total;
	if (unit == 0)
	{
		finsh_printf("%12d%12d%12d%11d%%\n",total, used, free, usage);
	}
	else
	{
		total = total / mul;
		used = used / mul;
		free = free / mul;
		finsh_printf("%10d %c%10d %c%10d %c%11d%%\n",total, unit, used, unit, free, unit,  usage);
	}
	
#endif	
	
	object_split(80);
#endif	

	return ret;
}


int finsh_system_uname(int argc, char **argv)
{
	finsh_printf("FreeRTOS %s, ",os_get_version());
	finsh_printf("%s %s, ", __DATE__, __TIME__);
	
#if defined(__CC_ARM) 		        	/* ARM Compiler */
	finsh_printf("ARMCC V%d.%02d(build %d) ", __ARMCC_VERSION/1000000, (__ARMCC_VERSION/10000)%100, __ARMCC_VERSION%1000);
#elif defined (__IAR_SYSTEMS_ICC__)     /* for IAR Compiler */

#elif defined (__GNUC__)                /* GNU GCC Compiler */
	finsh_printf("GCC V%d.%d.%d ", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__);
#elif defined (_MSC_VER)
	
#else
    #error not supported tool chain
#endif
	
	finsh_printf("\n");
	
	return 0;
}





#endif









